Skip to content

Use process shim in WorkerJavaScriptBackend - #37

Merged
aron-cf merged 9 commits into
stack/2-worker-javascript-examplefrom
stack/3-process-shim
Aug 3, 2026
Merged

aron-cf merged 9 commits into
stack/2-worker-javascript-examplefrom
stack/3-process-shim

Conversation

@aron-cf

@aron-cf aron-cf commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Code running in the worker-javascript backend had no process. A module could not read an environment variable, consume standard input, or write to standard output and standard error the way ordinary Node-style code expects. This change installs a process shim in the runner and threads the pieces it needs through the execution path.

The caller supplies env and stdin on the exec options. These flow through the runtime router and into the runner, which installs globalThis.process before user code runs. Only the values the caller passes are visible through process.env; the host environment is never exposed. process.stdin reads back the caller's bytes as a non-interactive, always-ends stream, bounded by a new maxStdinBytes ceiling. process.cwd() returns the execution's working directory, and process.argv and process.platform carry inert defaults.

Output is captured with stream identity preserved. console.log and console.info and direct process.stdout writes route to standard output; console.warn, console.error, and process.stderr writes route to standard error. Each is byte-accurate: a raw write is not given a trailing newline it did not have, and a console line keeps the one it adds. The capture stays bounded by the existing per-stream byte and event ceilings.

The client-facing exec options also gained env and stdin, so callers reaching the runtime through a Workspace stub can pass them; both survive the capnweb boundary unchanged. The worker-javascript example forwards env and stdin from its exec route, and its README shows a recipe that pipes standard input and reads an environment value.

Verify with npm test --workspace @cloudflare/computer, which exercises the shim end to end against the real Worker Loader, or post a module to the example that reads process.env and process.stdin.

@pkg-pr-new

pkg-pr-new Bot commented Aug 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/computer/@cloudflare/computer@37

commit: 4e782d0

@aron-cf
aron-cf force-pushed the stack/3-process-shim branch from 4e782d0 to 9cc0f86 Compare August 1, 2026 17:31
function errorJSON(error: unknown, status: number): Response {
const message = error instanceof Error ? error.message : String(error);
const code = (error as { code?: string }).code;
return new Response(JSON.stringify({ error: message, code }), {
@aron-cf
aron-cf force-pushed the stack/3-process-shim branch from 9cc0f86 to 12bd98f Compare August 3, 2026 10:18
aron-cf added 8 commits August 3, 2026 10:31
…cript backend

Executions now accept an env map that surfaces inside the module as
process.env. The runtime forwards env through the module exec path, the
backend passes it as evaluate context alongside the working directory,
and the runner installs a process object before importing user code.

Only caller-supplied variables are visible; the host process
environment is never exposed. The runner replaces globalThis.process,
falling back to defineProperty and then to reassigning process.env when
the nodejs_compat global resists replacement, so the override holds
whether or not the runtime pre-populated the global.
…ript backend

Executions accept a stdin value, passed as bytes or a string, that the
module reads through process.stdin. The runtime forwards it down the
module exec path, the backend normalizes it to bytes, bounds it by a
new maxStdinBytes option, and hands it to the runner as evaluate
context. The runner shims process.stdin as a non-TTY async iterable
that yields the supplied bytes once and then ends, so both for-await
and manual iteration read to completion.
…te streams

The runner captured console output into a single list tagged with
textual level prefixes, which the backend mapped back to stdout or
stderr. Replace that with stream-tagged capture: console.log and
console.info record to stdout, console.warn and console.error to
stderr, and process.stdout.write and process.stderr.write record their
raw bytes to the matching stream without an added newline.

Console lines carry their own trailing newline, so the backend now
emits each captured entry verbatim rather than appending one. The
per-stream byte and event ceilings and the truncation marker are
preserved.
Add an end-to-end case asserting process.cwd() tracks the exec cwd and
that argv and platform carry their inert defaults, pinning the shim
surface that the env, stdin, and stdout work left untested.
The host and stub exec paths gained env and stdin, but the
client-facing RuntimeExecOptions still omitted them, so callers reaching
the runtime through getWorkspace(stub) could not pass either. Add both
fields; the client already forwards the whole options object, and env
maps and byte stdin survive the capnweb boundary unchanged.
The exec handler now forwards env and stdin from the request body into
runtime.exec, so a posted module can read process.env and process.stdin.
Document the extended request shape and add a smoke-test recipe that
pipes stdin and reads an env value.
Add a section to the JavaScript runtime doc describing the process shim:
caller-supplied env exposed through process.env with the host
environment hidden, caller-supplied stdin as a non-interactive
async-iterable bounded by maxStdinBytes, stdout and stderr capture with
console routing, and inert argv, cwd, and platform. List maxStdinBytes
among the configurable byte limits.

Add a test asserting an oversized stdin fails the run before the loader
is invoked.
Caller-supplied env crossed the boundary unchecked and unbounded while
source, input, and stdin all had a ceiling. Add assertEnv to reject a
non-object env or a non-string value and to bound the total key and
value bytes with a new maxEnvBytes option, defaulting to one mebibyte.
Harden normalizeStdin to reject a value that is neither a string nor a
Uint8Array rather than letting it slip past the stdin ceiling check.
@aron-cf
aron-cf force-pushed the stack/3-process-shim branch from 12bd98f to eae3d73 Compare August 3, 2026 10:39
The starting defaults were tuned conservatively and proved too tight in
practice. Raise the execution timeout ceiling to three minutes and the
default to sixty seconds, the source and input byte ceilings to one
mebibyte each, the retention window to sixty minutes, the concurrent
execution ceiling to twenty-four, and the concurrent capability call
ceiling to thirty-two. Update the backend documentation to match and
keep the concurrency-cap test pinned to a single execution so it still
exercises the ceiling.
@aron-cf
aron-cf merged commit 8a580fd into main Aug 3, 2026
9 of 10 checks passed
@aron-cf
aron-cf deleted the stack/3-process-shim branch August 3, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants